#include "Acceptor.h"
#include "Logger.h"

#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <unistd.h>

static int createNonblocking()
{
    /**
     * int socket(int domain, int type, int protocol);
     * domain: 指定套接字使用的协议族。常用的有AF_INET（IPv4网络协议）、AF_INET6（IPv6网络协议）等。
     * type: 指定套接字类型。常用的有SOCK_STREAM（流式套接字，对应TCP协议）和SOCK_DGRAM（数据报套接字，对应UDP协议）。
     * protocol: 通常设置为0，让操作系统自动选择type对应的默认协议，例如TCP或UDP。
    */
    int sockfd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
    if(sockfd < 0)
    {
        LOG_FATAL("%s:%s:%d listen socket create err:%d \n", __FILE__, __FUNCTION__, __LINE__ , errno);
    }
    return sockfd;
}

Acceptor::Acceptor(EventLoop* loop,const InetAddress &listenAddr,bool reuseport)
    : loop_(loop)
    , acceptSocket_(createNonblocking()) //创建套接字
    , acceptChannel_(loop, acceptSocket_.fd())
    , listening_(false)
{
    acceptSocket_.setReuseAddr(true);
    acceptSocket_.setReusePort(true);
    acceptSocket_.bindAddress(listenAddr); //绑定套接字
    // TcpServer::start()->Acceptor.listen->有新用户连接，要执行一个回调(connfd->channel->subloop)
    // baseloop监听到acceptChannel_(listenfd)有事件发生=>执行回调函数
    acceptChannel_.setReadCallback(std::bind(&Acceptor::handleRead,this));
}
Acceptor::~Acceptor()
{
    acceptChannel_.disableAll();
    acceptChannel_.remove();
}

void Acceptor::listen()
{
    listening_ = true;
    acceptSocket_.listen(); //监听
    acceptChannel_.enableReading(); //将acceptChannel注册到Poller
} 

//listenfd有事件发生时，也就是有新用户连接时
void Acceptor::handleRead()
{
    InetAddress peerAddr;
    int connfd = acceptSocket_.accept(&peerAddr);
    if(connfd>=0)
    {
        if(newConnectionCallback_)
        {
            newConnectionCallback_(connfd,peerAddr); //轮询找到subloop,唤醒，分发当前的新客户端的Channel
        }
        else
        {
            ::close(connfd);
        }
    }
    else
    {
        LOG_FATAL("%s:%s:%d accept err:%d \n", __FILE__, __FUNCTION__, __LINE__ , errno);
        if(errno == EMFILE)
        {
            LOG_FATAL("%s:%s:%d sockfd reached limit! \n", __FILE__, __FUNCTION__, __LINE__ );
        }
    }
}
